﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

namespace Dotnet.DB
{
    partial class DbBase
    {
        public class DatabaseFindErrorEventArgs : EventArgs
        {
            public string Msg { get; set; }
            public Exception Ex { get; set; }
        }

        private EventHandler<DatabaseFindStringEventArgs> _findString;
        private EventHandler<DatabaseTableFilterEventArgs> _tableFilter;
        private EventHandler<DatabaseFindErrorEventArgs> _findError;
        private ActionBlock<ActionBlockClass> actionBlock = null;
        #region 自定义事件
        public event EventHandler<DatabaseFindStringEventArgs> FindString
        {
            add { _findString += value; }
            remove { _findString -= value; }
        }
        public event EventHandler<DatabaseTableFilterEventArgs> TableFilter
        {
            add { _tableFilter += value; }
            remove { _tableFilter -= value; }
        }
        protected virtual void OnTableFilter(DatabaseTableFilterEventArgs e)
        {
            EventHandler<DatabaseTableFilterEventArgs> temp = System.Threading.Volatile.Read(ref _tableFilter);
            if (temp != null)
            {
                temp(this, e);
            }
        }
        protected virtual void OnFindString(DatabaseFindStringEventArgs e)
        {
            EventHandler<DatabaseFindStringEventArgs> temp = System.Threading.Volatile.Read(ref _findString);
            if (temp != null)
            {
                temp(this, e);
            }
        }

        public event EventHandler<DatabaseFindErrorEventArgs> FindError
        {
            add { _findError += value; }
            remove { _findError -= value; }
        }
        protected virtual void OnFindError(DatabaseFindErrorEventArgs e)
        {
            EventHandler<DatabaseFindErrorEventArgs> temp = System.Threading.Volatile.Read(ref _findError);
            if (temp != null)
            {
                temp(this, e);
            }
        }
        private class ActionBlockClass
        {
            public DataTable Dt { get; set; }
            public int TableIndex { get; set; }
            public string TableName { get; set; }

        }
        #endregion
        public void FindKeywordInTables(string conn, List<string> tables, string keyword)
        {
            int tableCount = 0;
            actionBlock = new ActionBlock<ActionBlockClass>((t) => {
                foreach (DataColumn dc in t.Dt.Columns)
                {
                    try
                    {
                        if (dc.DataType.Name.ToLower().Contains("time"))
                            continue;
                        string strSql = GetSql(t.Dt.TableName, dc.ColumnName, keyword);
                        double usetime = 0;
                        DataTable dt1 = ExecuteDataTableAsync(conn, strSql, out usetime);
                        OnFindString(new DatabaseFindStringEventArgs()
                        {
                            TableName =t.TableName,
                            ColumnName = dc.ColumnName,
                            Sql = strSql,
                            UseTime = usetime,
                            RowsCount = dt1.Rows.Count,
                            TableIndex=t.TableIndex,
                            ColumnIndex = dc.Ordinal+1
                        });
                    }
                    catch (Exception ex)
                    {
                        OnFindError(new DatabaseFindErrorEventArgs() { Msg = ex.Message, Ex = ex });
                    }
                }
            });
            Parallel.ForEach(tables, new ParallelOptions() { MaxDegreeOfParallelism = 8 },
                (item) =>
                {
                    try
                    {
                        double time = 0;
                        string sql = GetTop1Sql(item, 100);
                        DataTable dt =ExecuteDataTableAsync(conn, sql, out time);
                        System.Threading.Interlocked.Increment(ref tableCount);
                        if (dt != null)
                        {
                            dt.TableName = item;
                            OnTableFilter(new DatabaseTableFilterEventArgs()
                            {
                                TableName = item,
                                Sql = sql,
                                RowsCount = dt.Rows.Count,
                                TableIndex = tableCount,
                                UseTime = time
                            });
                            if (dt.Rows.Count > 0)
                            {
                                actionBlock.Post(new ActionBlockClass() { Dt=dt,TableName=item,TableIndex=tableCount });
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        OnFindError(new DatabaseFindErrorEventArgs() { Msg = ex.Message, Ex = ex });
                    }
                });
        }
        #region 虚方法
        public virtual DataTable ExecuteDataTableAsync(string connString,string strSql,out double usetime)
        {
            throw new NotImplementedException("未实现");
        }
        public virtual object ExecuteScalarAsync(string connString,string strSql,out double usetime)
        {
            throw new NotImplementedException("未实现");
        }

        public virtual string GetSql(string tableName)
        {
            return $"select *from [{tableName}]";
        }
        public virtual string GetTop1Sql(string tableName,int top)
        {
            string strSql = $"select top {top} *from [{tableName}]";
            return strSql;
        }

        public virtual string GetSql(string tableName, string colName,string value)
        {
            //select* from(select iif({colName} is null,'',{ colName}) as {}1, *from[ygxx]) aa where ygmc1 like '%123%'
            string strSql= $"select *from [{tableName}] where cast([{colName}] as varchar(4000)) like '%{value}%'";
            //string strSql = $"select* from(select iif({colName} is null,'',{colName}) as {colName}1, *from[{tableName}]) aa where {colName}1 like '%{value}%'";
            return strSql;
        }
        #endregion
    }
}
